/*
尽可能还原 Promise 中的每一个 API, 并通过注释的方式描述思路和原理.
    1.promise 是一个类，在执行这个类的时候需要传递一个执行器进去，执行器会立即执行
    2.promise 三种状态 分别为：成功fulfilled 失败rejected 等待 pending 一旦状态确定就不可更改。
    3.resolve和reject函数是用来更改状态的
*/

const PENDING = 'pending'; // 等待
const FULFILLED = 'fulfilled'; // 成功
const REJECTED = 'rejected'; // 失败


class MyPromise {
    constructor (excutor) {
      try{
        excutor(this.resolve,this.reject)
      }catch (e) {
        this.reject(e)
      }
    }
    status = PENDING
    value = undefined
    reason = undefined
    successCallback = []
    failCallback = []
    // 箭头函数，更改状态
    resolve= value =>{
      // 状态不可逆
      if(this.status !== PENDING) return
      this.status = FULFILLED
      this.value = value
      // 成功回调
      while(this.successCallback.length){
        this.successCallback.shift()()
      }
    }
    reject = reason =>{
      if(this.status !== PENDING) return
      this.status = REJECTED
      this.reason = reason
      while(this.failCallback.length){
        this.failCallback.shift()()
      }
    }
    then(successCallback,failCallback) {
      // 参数可选
      successCallback = successCallback ? successCallback : value => value;
      failCallback = failCallback ? failCallback: reason => { throw reason };
      let promise2 = new MyPromise((resolve,reject)=>{
        if(this.status === FULFILLED) {
          // 异步获取promise2
          setTimeout(() => {
            try{
              let x = successCallback(this.value)
              resolvePromise(promise2, x, resolve, reject)
            }catch(e){
              reject(e)
            }
          }, 0)
        }else if(this.status === REJECTED) {
          setTimeout(() => {
            try{
              let x = failCallback(this.reason)
              resolvePromise(promise2, x, resolve, reject)
            }catch(e){
              reject(e)
            }
          }, 0)
        }else{
          //pending状态,存储回调函数,异步情况存储多个
          this.successCallback.push(()=>{
            setTimeout(() => {
              try{
                let x = successCallback(this.value)
                resolvePromise(promise2, x, resolve, reject)
              }catch(e){
                reject(e)
              }
            }, 0)
          })
          this.failCallback.push(()=>{
            setTimeout(() => {
              try{
                let x = failCallback(this.reason)
                resolvePromise(promise2, x, resolve, reject)
              }catch(e){
                reject(e)
              }
            }, 0)
          })
        }
      })
      return promise2
    }
    finally (callback) {
      // 借助resolve返回Promise对象
      return this.then(value => {
        return MyPromise.resolve(callback()).then(() => value);
      }, reason => {
        return MyPromise.resolve(callback()).then(() => { throw reason })
      })
    }
    catch (failCallback) {
      return this.then(undefined, failCallback)
    }
    static all (array) {
      let result = []
      let index = 0
      return new MyPromise((resolve, reject) => {
        function addData (key, value) {
          result[key] = value
          index++
          // 异步
          if(index === array.length) {
            resolve(result)
          }
        }
        for(let i = 0; i < array.length; i++) {
          let current = array[i]
          // 判断类型
          if(current instanceof MyPromise) {
            current.then(value => addData(i, value), reason => reject(reason))
          }else {
            addData(i, array[i])
          }
        }
      })
    }
    static resolve (value) {
      //判断类型 Promise对象返回本身
      if (value instanceof MyPromise) return value
      //非Promise对象创建一个
      return new MyPromise(resolve => resolve(value))
    }
  }
  
  function resolvePromise(promise2, x, resolve, reject) {
    // 抛出异常
    if(promise2 === x){
      return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
    }
    if(x instanceof MyPromise) {
      x.then(resolve, reject)
    }else{
      resolve(x)
    }
  }
  
  module.exports = MyPromise;